home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / TCPUSER.C < prev    next >
C/C++ Source or Header  |  1996-12-23  |  10KB  |  428 lines

  1. /* User calls to TCP
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include "global.h"
  5. #include "timer.h"
  6. #include "mbuf.h"
  7. #include "netuser.h"
  8. #include "internet.h"
  9. #include "iface.h"
  10.  
  11. #if !defined(_lint)
  12. static char rcsid[] OPTIONAL = "$Id: tcpuser.c,v 1.13 1996/12/23 22:44:37 root Exp root $";
  13. #endif
  14.  
  15. int16 Tcp_window = DEF_WND;
  16.  
  17.  
  18. /* open a tcp connection */
  19. struct tcb *
  20. open_tcp (lsocket, fsocket, mode, thewindow, r_upcall, t_upcall, s_upcall, tos, user)
  21. struct socket *lsocket;        /* Local socket */
  22. struct socket *fsocket;        /* Remote socket */
  23. int mode;            /* Active/passive/server */
  24. int16 thewindow;        /* Receive window (and send buffer) sizes */
  25. void (*r_upcall) (struct tcb *, int16);    /* Function to call when data arrives */
  26. void (*t_upcall) (struct tcb *, int16);    /* Function to call when ok to send more data */
  27. void (*s_upcall) (struct tcb *, int, int);    /* Function to call when connection state changes */
  28. int tos;
  29. int user;            /* User linkage area */
  30. {
  31. struct connection conn;
  32. register struct tcb *tcb;
  33. struct iface *ifp = NULL;
  34. struct route *rp;
  35.  
  36.     if (lsocket == NULLSOCK) {
  37.         Net_error = INVALID;
  38.         return NULLTCB;
  39.     }
  40.     conn.local.address = lsocket->address;
  41.     conn.local.port = lsocket->port;
  42.     if (fsocket != NULLSOCK) {
  43.         conn.remote.address = fsocket->address;
  44.         conn.remote.port = fsocket->port;
  45.     } else {
  46.         conn.remote.address = 0;
  47.         conn.remote.port = 0;
  48.     }
  49.     if ((tcb = lookup_tcb (&conn)) == NULLTCB) {
  50.         /* If we are about to start a new connection,
  51.          * but don't have a route, disallow it ! - WG7J
  52.          */
  53.         if (mode == TCP_ACTIVE) {
  54.             /* Is this to ourself ? */
  55.             if ((ifp = ismyaddr (conn.remote.address)) == NULL) {
  56.                 /* No, do we have a route ? */
  57.                 if ((rp = rt_lookup (conn.remote.address)) == NULL) {
  58.                     /* We have no route to this system ! */
  59.                     Net_error = NOROUTE;
  60.                     return NULLTCB;
  61.                 } else
  62.                     ifp = rp->iface;
  63.             }
  64.         }
  65.         if ((tcb = create_tcb (&conn)) == NULLTCB) {
  66.             Net_error = NO_MEM;
  67.             return NULLTCB;
  68.         }
  69.     } else {        /* if(tcb->state != TCP_LISTEN){
  70.           * prevent multiple servers being added to the
  71.           * server list in socket.c ! - WG7J
  72.           * Note that this bug still exists in vanilla KA9Q */
  73.         Net_error = CON_EXISTS;
  74.         return NULLTCB;
  75.     }
  76.     tcb->user = user;
  77.     if (thewindow != 0)
  78.         tcb->window = tcb->rcv.wnd = thewindow;
  79.     else {
  80.         if (ifp)
  81.             tcb->window = tcb->rcv.wnd = ifp->tcp->window;
  82.         else
  83.             tcb->window = tcb->rcv.wnd = Tcp_window;
  84.     }
  85.     tcb->snd.wnd = 1;    /* Allow space for sending a SYN */
  86.     tcb->r_upcall = r_upcall;
  87.     tcb->t_upcall = t_upcall;
  88.     tcb->s_upcall = s_upcall;
  89.     tcb->tos = (char) tos;
  90.     switch (mode) {
  91.         case TCP_SERVER:
  92.             tcb->flags.clone = 1;    /*lint !e616 Note fall-thru */
  93.         case TCP_PASSIVE:
  94.             /* Point to the default tcp parameters */
  95.             tcb->parms = &def_iftcp;
  96.             setstate (tcb, TCP_LISTEN);
  97.             break;
  98.         case TCP_ACTIVE:
  99.             /* We already have a route, found earlier.
  100.              * Point to this interface's tcp parameters - WG7J
  101.              */
  102.             tcb->parms = (ifp) ? ifp->tcp : 0;
  103.             /* Set the interface specific mss values - WG7J */
  104.             tcb->cwind = tcb->mss = tcb->parms->mss;
  105.             /* Find a known rtt or load interface default - WG7J */
  106.             set_irtt (tcb);
  107.  
  108.             /* Send SYN, go into TCP_SYN_SENT state */
  109.             tcb->flags.active = 1;
  110.             send_syn (tcb);
  111.             setstate (tcb, TCP_SYN_SENT);
  112.             tcp_output (tcb);
  113.             break;
  114.         default:
  115.             break;
  116.     }
  117.     return tcb;
  118. }
  119.  
  120.  
  121. /* User send routine */
  122. int
  123. send_tcp (tcb, bp)
  124. register struct tcb *tcb;
  125. struct mbuf *bp;
  126. {
  127. int16 cnt;
  128.  
  129.     if (tcb == NULLTCB || bp == NULLBUF) {
  130.         free_p (bp);
  131.         Net_error = INVALID;
  132.         return -1;
  133.     }
  134.     cnt = len_p (bp);
  135.     switch (tcb->state) {
  136.         case TCP_CLOSED:
  137.             free_p (bp);
  138.             Net_error = NO_CONN;
  139.             return -1;
  140.         case TCP_LISTEN:
  141.             if (tcb->conn.remote.address == 0 && tcb->conn.remote.port == 0) {
  142.                 /* Save data for later */
  143.                 append (&tcb->sndq, bp);
  144.                 tcb->sndcnt += cnt;
  145.                 break;
  146.             }
  147.             /* Change state from passive to active */
  148.             tcb->flags.active = 1;
  149.             send_syn (tcb);
  150.             setstate (tcb, TCP_SYN_SENT);    /*lint !e616 Note fall-thru */
  151.         case TCP_SYN_SENT:
  152.         case TCP_SYN_RECEIVED:
  153.         case TCP_ESTABLISHED:
  154.         case TCP_CLOSE_WAIT:
  155.             append (&tcb->sndq, bp);
  156.             tcb->sndcnt += cnt;
  157.             tcp_output (tcb);
  158.             break;
  159.         case TCP_FINWAIT1:
  160.         case TCP_FINWAIT2:
  161.         case TCP_CLOSING:
  162.         case TCP_LAST_ACK:
  163.         case TCP_TIME_WAIT:
  164.             free_p (bp);
  165.             Net_error = CON_CLOS;
  166.             return -1;
  167.         default:
  168.             break;
  169.     }
  170.     return (int) cnt;
  171. }
  172.  
  173. /* User receive routine */
  174. int
  175. recv_tcp (tcb, bpp, cnt)
  176. register struct tcb *tcb;
  177. struct mbuf **bpp;
  178. int16 cnt;
  179. {
  180.     if (tcb == NULLTCB || bpp == (struct mbuf **) NULL) {
  181.         Net_error = INVALID;
  182.         return -1;
  183.     }
  184.     if (tcb->rcvcnt == 0) {
  185.         /* If there's nothing on the queue, our action depends on what state
  186.          * we're in (i.e., whether or not we're expecting any more data).
  187.          * If no more data is expected, then simply return 0; this is
  188.          * interpreted as "end of file". Otherwise return -1.
  189.          */
  190.         switch (tcb->state) {
  191.             case TCP_LISTEN:
  192.             case TCP_SYN_SENT:
  193.             case TCP_SYN_RECEIVED:
  194.             case TCP_ESTABLISHED:
  195.             case TCP_FINWAIT1:
  196.             case TCP_FINWAIT2:
  197.                 Net_error = WOULDBLK;
  198.                 return -1;
  199.             case TCP_CLOSED:
  200.             case TCP_CLOSE_WAIT:
  201.             case TCP_CLOSING:
  202.             case TCP_LAST_ACK:
  203.             case TCP_TIME_WAIT:
  204.                 *bpp = NULLBUF;
  205.                 return 0;
  206.             default:
  207.                 break;
  208.         }
  209.     }
  210.     /* cnt == 0 means "I want it all" */
  211.     if (cnt == 0)
  212.         cnt = tcb->rcvcnt;
  213.     /* See if the user can take all of it */
  214.     if (tcb->rcvcnt <= cnt) {
  215.         cnt = tcb->rcvcnt;
  216.         *bpp = tcb->rcvq;
  217.         tcb->rcvq = NULLBUF;
  218.     } else {
  219.         *bpp = ambufw (cnt);
  220.         (void) pullup (&tcb->rcvq, (*bpp)->data, cnt);
  221.         (*bpp)->cnt = cnt;
  222.     }
  223.     tcb->rcvcnt -= cnt;
  224.     tcb->rcv.wnd += cnt;
  225.     /* Do a window update if it was closed */
  226.     if (cnt == tcb->rcv.wnd) {
  227.         tcb->flags.force = 1;
  228.         tcp_output (tcb);
  229.     }
  230.     return (int) cnt;
  231. }
  232.  
  233.  
  234. /* This really means "I have no more data to send". It only closes the
  235.  * connection in one direction, and we can continue to receive data
  236.  * indefinitely.
  237.  */
  238. int
  239. close_tcp (tcb)
  240. register struct tcb *tcb;
  241. {
  242.     if (tcb == NULLTCB) {
  243.         Net_error = INVALID;
  244.         return -1;
  245.     }
  246.     switch (tcb->state) {
  247.         case TCP_CLOSED:
  248.             return 0;    /* Unlikely */
  249.         case TCP_LISTEN:
  250.         case TCP_SYN_SENT:
  251.             close_self (tcb, NORMAL);
  252.             return 0;
  253.         case TCP_SYN_RECEIVED:
  254.         case TCP_ESTABLISHED:
  255.             tcb->sndcnt++;
  256.             tcb->snd.nxt++;
  257.             setstate (tcb, TCP_FINWAIT1);
  258.             tcp_output (tcb);
  259.             return 0;
  260.         case TCP_CLOSE_WAIT:
  261.             tcb->sndcnt++;
  262.             tcb->snd.nxt++;
  263.             setstate (tcb, TCP_LAST_ACK);
  264.             tcp_output (tcb);
  265.             return 0;
  266.         case TCP_FINWAIT1:
  267.         case TCP_FINWAIT2:
  268.         case TCP_CLOSING:
  269.         case TCP_LAST_ACK:
  270.         case TCP_TIME_WAIT:
  271.             Net_error = CON_CLOS;
  272.             return -1;
  273.         default:
  274.             break;
  275.     }
  276.     return -1;        /* "Can't happen" */
  277. }
  278.  
  279.  
  280. /* Delete TCB, free resources. The user is not notified, even if the TCB is
  281.  * not in the TCP_CLOSED state. This function should normally be called by the
  282.  * user only in response to a state change upcall to TCP_CLOSED state.
  283.  */
  284. int
  285. del_tcp (conn)
  286. struct tcb *conn;
  287. {
  288. register struct tcb *tcb;
  289. struct tcb *tcblast = NULLTCB;
  290. struct reseq *rp, *rp1;
  291.  
  292.     /* Remove from list */
  293.     for (tcb = Tcbs; tcb != NULLTCB; tcblast = tcb, tcb = tcb->next)
  294.         if (tcb == conn)
  295.             break;
  296.     if (tcb == NULLTCB) {
  297.         Net_error = INVALID;
  298.         return -1;    /* conn was NULL, or not on list */
  299.     }
  300.     if (tcblast != NULLTCB)
  301.         tcblast->next = tcb->next;
  302.     else
  303.         Tcbs = tcb->next;    /* was first on list */
  304.  
  305.     stop_timer (&tcb->timer);
  306.     for (rp = tcb->reseq; rp != NULLRESEQ; rp = rp1) {
  307.         rp1 = rp->next;
  308.         free_p (rp->bp);
  309.         free ((char *) rp);
  310.     }
  311.     tcb->reseq = NULLRESEQ;
  312.     free_p (tcb->rcvq);
  313.     free_p (tcb->sndq);
  314.     free ((char *) tcb);
  315.     return 0;
  316. }
  317.  
  318.  
  319. /* Return 1 if arg is a valid TCB, 0 otherwise */
  320. int
  321. tcpval (tcb)
  322. struct tcb *tcb;
  323. {
  324. register struct tcb *tcb1;
  325.  
  326.     if (tcb == NULLTCB)
  327.         return 0;    /* Null pointer can't be valid */
  328.     for (tcb1 = Tcbs; tcb1 != NULLTCB; tcb1 = tcb1->next) {
  329.         if (tcb1 == tcb)
  330.             return 1;
  331.     }
  332.     return 0;
  333. }
  334.  
  335.  
  336. /* Kick a particular TCP connection */
  337. int
  338. kick_tcp (tcb)
  339. register struct tcb *tcb;
  340. {
  341.     if (!tcpval (tcb))
  342.         return -1;
  343.     tcb->flags.force = 1;    /* Send ACK even if no data */
  344.     tcp_timeout (tcb);
  345.     return 0;
  346. }
  347.  
  348.  
  349. /* Kick all TCP connections to specified address; return number kicked */
  350. int
  351. kick (addr)
  352. uint32 addr;
  353. {
  354. register struct tcb *tcb;
  355. int cnt = 0;
  356.  
  357.     for (tcb = Tcbs; tcb != NULLTCB; tcb = tcb->next) {
  358.         if (tcb->conn.remote.address == addr) {
  359.             (void) kick_tcp (tcb);
  360.             cnt++;
  361.         }
  362.     }
  363.     return cnt;
  364. }
  365.  
  366.  
  367. /* Clear all TCP connections */
  368. void
  369. reset_all ()
  370. {
  371. struct tcb *tcb, *tcb1;
  372.  
  373.     for (tcb = Tcbs; tcb != NULLTCB; tcb = tcb1) {
  374.         tcb1 = tcb->next;
  375.         reset_tcp (tcb);
  376.     }
  377.  
  378.     kwait (NULL);    /* Let the RSTs go forth */
  379. }
  380.  
  381.  
  382. void
  383. reset_tcp (tcb)
  384. register struct tcb *tcb;
  385. {
  386. struct tcp fakeseg;
  387. struct ip fakeip;
  388.  
  389.     if (tcb == NULLTCB)
  390.         return;
  391.     if (tcb->state != TCP_LISTEN) {
  392.         /* Compose a fake segment with just enough info to generate the
  393.          * correct RST reply
  394.          */
  395.         memset ((char *) &fakeseg, 0, sizeof (fakeseg));
  396.         memset ((char *) &fakeip, 0, sizeof (fakeip));
  397.         fakeseg.dest = tcb->conn.local.port;
  398.         fakeseg.source = tcb->conn.remote.port;
  399.         fakeseg.flags.ack = 1;
  400.         /* Here we try to pick a sequence number with the greatest likelihood
  401.          * of being in his receive window.
  402.          */
  403.         fakeseg.ack = tcb->snd.nxt + tcb->snd.wnd - 1;
  404.         fakeip.dest = tcb->conn.local.address;
  405.         fakeip.source = tcb->conn.remote.address;
  406.         fakeip.tos = tcb->tos;
  407.         reset (&fakeip, &fakeseg);
  408.     }
  409.     close_self (tcb, RESET);
  410. }
  411.  
  412.  
  413. void 
  414. set_irtt (struct tcb *tcb)
  415. {
  416. struct tcp_rtt *tp;
  417.  
  418.     if ((tp = rtt_get (tcb->conn.remote.address)) != NULLRTT) {
  419.         tcb->srtt = tp->srtt;
  420.         tcb->mdev = tp->mdev;
  421.     } else {
  422.         tcb->srtt = tcb->parms->irtt;
  423.         tcb->mdev = 0;
  424.     }
  425.     /* Initialize timer intervals */
  426.     set_timer (&tcb->timer, tcb->srtt);
  427. }
  428.